// 封装tcp套接字
// 采用的是模板方法模式

#include "Common.hpp"
#include "Log.hpp"
#include "InetAddr.hpp"

#include <string>
#include <sys/types.h>
#include <iostream>

uint16_t global_port = 8080;
int global_sockfd = -1;

// TcpSocket是一个socket管理者  在外部调用接口，将实现的细节进行封装，一切的实现都是通过socket管理者去实现
namaspace ns_socket
{
    using namespace LogModule;
    class Socket;

    using SockPtr = std::shared_ptr<Socket>;
    class Socket
    {
    public:
        virtual ~Socket() = default;
        virtual void SocketOrDie() = 0;
        virtual void SetSocketOpt() = 0; // 在服务器主动断开后，不会长时间处于wait_time
        virtual bool BindOrDie(int port) = 0;
        virtual bool ListenOrDie() = 0;
        virtual SockPtr Accept(InetAddr *client) = 0;
        virtual void Close() = 0;
        virtual int Recv(std::string *out) = 0;
        virtual int Send(const std::string &in) = 0;
        virtual int Fd() = 0;

        void BuildSocket(int port)
        {
            SocketOrDie();
            SetSocketOpt();
            BindOrDie(port);
            ListenOrDie();
        }
    };

    class Tcpsocket : public Socket
    {
    public:
        Tcpsocket() : _sockfd(global_sockfd)
        {
        }

        Tcpsocket(int newsockfd) : _sockfd(newsockfd)
        {
        }

        virtual void SocketOrDie() override
        {
            _sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
            if (_sockfd < 0)
            {
                std::cout << "socket error" << std::endl;
                exit(SOCKET_ERR);
            }
            std::cout << "socket success" << std::endl;
        }

        virtual void SetSocketOpt() = 0; // 在服务器主动断开后，不会长时间处于wait_time
        virtual bool BindOrDie(int port) override
        {
            InetAddr addr(port);
            int return = ::bind(_sockfd, addr.NetAddr(), addr.NetAddrLen());
            if (return < 0)
            {
                std::cout << "bind error" << std::endl;
                exit(BIND_ERR);
            }
            std::cout << "bind success" << std::endl;
        }
        virtual bool ListenOrDie() override
        {
            int return = ::listen(_sockfd, 8);
            if (return < 0)
            {
                std::cout << "listen error" << std::endl;
                exit(LISTEN_ERR);
            }
            std::cout << "listen success" << std::endl;
        }
        virtual SockPtr Accept(InetAddr *client) override
        {
            // 将accept的数据要存入client带出
            if (!client)
                return nullptr;
            sockaddr_in peer;
            socklen_t len = client->NetAddrLen();

            int newsockfd = ::accept(_sockfd, CONV(&peer), &len);
            if (sockfd < 0)
            {
                std::cout << "accept error" << std::endl;
                exit(ACCEPT_ERR);
            }
            std::cout << "accept success" << std::endl;
            client->SetAddr(peer, len);
            return make_shared<Tcpsocket>(newsockfd);
        }

        virtual void Close() override
        {
            ::close(sockfd);
        }
        virtual int Recv(std::string *out) override
        {
            char buffer[1024 * 8];
            int size = ::recv(_sockfd, buffer, sizeof(buffer) - 1, 0);
            if (size > 0)
            {
                buffer[size] = 0;
                *out = buffer;
            }
            return size;
        }
        virtual int Send(const std::string &in)
        {
            int size = ::send(_sockfd, in.c_str(), sizeof(in.c_str()), 0);
            return size;
        }
        
        virtual int Fd() override
        {
            return _sockfd;
        }

        ~Tcpsocket() override
        {
        }

    private:
        int _sockfd;
    };
}
